//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008-2010, Shane J. M. Liesegang
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright 
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of any 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////////

#include "Brain.h"
#include "Sentient.h"
#include "TextRendering.h"
#include "MathUtil.h"

AIBrain::AIBrain()
{
	_current = _brainStateTable.end();
	_drawMe = false;
}

AIBrain::~AIBrain()
{
	GotoNullState();
	// clean up states
	BrainStateTable::iterator itr = _brainStateTable.begin();
	for(; itr != _brainStateTable.end(); itr++)
	{
		AIBrainState* pState = (*itr).second;
		delete pState;
	}
}

void AIBrain::AddState(const String& id, AIBrainState* state)
{
	// remove existing state in this ID
	String useId = ToUpper(id);
	BrainStateTable::iterator itr = _brainStateTable.find(useId);
	if(itr != _brainStateTable.end())
	{
		// delete second
		delete itr->second;
	}

	state->Initialize(this);

	_brainStateTable[useId] = state;
}

void AIBrain::Update(float dt)
{
	if(_brainStateTable.size() == 0)
	{
		GetActor()->InitializeBrain();
		GetActor()->StartBrain();
	}

	if(_current == _brainStateTable.end())
		return;
	(*_current).second->Update(dt);

}

void AIBrain::GotoState(const String& id)
{
	String useId = ToUpper(id);
	BrainStateTable::iterator itr = _brainStateTable.find(useId);
	if(itr != _brainStateTable.end())
	{
		AIBrainState* pNextState = itr->second;
		AIBrainState* pLastState = NULL;
		if(_current != _brainStateTable.end())
		{
			_current->second->EndState(pNextState);
			pLastState = _current->second;
		}

		_current = itr;
		_current->second->BeginState(pLastState);
	}
}

void AIBrain::Render()
{
	if(!_drawMe)
		return;

	if(_current != _brainStateTable.end())
	{
		Vector2 screenCenter = MathUtil::WorldToScreen(GetActor()->GetPosition().X, GetActor()->GetPosition().Y);
		// Print some vals
		glColor3f(0,0.f, 1.f);
		DrawGameText(_current->first, "ConsoleSmall", (int)screenCenter.X, (int)screenCenter.Y);
	}
}

void AIBrain::GotoNullState()
{
        if( _current != _brainStateTable.end() )
                (*_current).second->EndState( NULL );

        _current = _brainStateTable.end();
}

void AIBrain::EnableDrawing(bool enable)
{
        _drawMe = enable;
}


void AIBrainState::Update(float dt)
{
        CustomUpdate(dt);
        for( unsigned int i = 0; i < _eventList.size(); i++ )
        {
                _eventList[i]->Update(dt);
        }
}


void AIBrainState::EndState( AIBrainState* nextState )
{
        CustomEndState( nextState );
        ClearEvents();
}

void AIBrainState::GotoState( const String& id )
{
        _brain->GotoState( id );
}

AIEvent* AIBrainState::RegisterEvent( AIEvent* newEvent )
{
        _eventList.push_back( newEvent );
        newEvent->SetBrain( _brain );
        return newEvent;
}

void AIBrainState::UnregisterEvent( AIEvent* oldEvent )
{
        for( EventList::iterator itr = _eventList.begin(); itr != _eventList.end(); itr++ )
        {
                if( (*itr) == oldEvent )
                {
                        _eventList.erase( itr );
                        StopEvent( oldEvent );
                        return;
                }
        }
}

void AIBrainState::ClearEvents()
{
        //stop and delete events
        for( unsigned int i = 0; i < _eventList.size(); i++ )
        {
                StopEvent( _eventList[i]);
        }
        _eventList.clear();
}


void AIBrainState::StopEvent( AIEvent* pEvent )
{
        pEvent->Stop();
        delete pEvent;
}